package main

import (
	"encoding/json"
	"fmt"
	"reflect"
	"time"
)

func main() {
	fmt.Println("<<<<<测试-Go语言的反射机制>>>>>")
	// x := 3.4
	// reflect_set_value(&x)
	// fmt.Println("main: ", x)

	// u := User{1, "tom", 22, time.Now()}
	// Poni(u)

	TestAnonymous()

	// TestCallMethod()
}

/*获取类型信息*/
func reflect_type(a interface{}) {
	t := reflect.TypeOf(a)
	fmt.Println("类型是：", t)
	// kind 可以获取具体的类型
	k := t.Kind()
	fmt.Println("具体的类型是：", k)

	switch k {
	case reflect.Float64:
		fmt.Println("a is float64")
	case reflect.String:
		fmt.Println("a is string")
	}
}

/*获取值信息*/
func reflect_value(a interface{}) {
	v := reflect.ValueOf(a)
	fmt.Println("值是：", v)
	// kind 可以获取具体的类型
	k := v.Kind()
	fmt.Println("具体类型是：", k)

	switch k {
	case reflect.Float64:
		fmt.Println("a is float64:", v.Float())
	case reflect.String:
		fmt.Println("a is string:", v.String())
	}
}

/*修改值信息*/
func reflect_set_value(a interface{}) {
	v := reflect.ValueOf(a)
	fmt.Println("值是：", v)
	// kind 可以获取具体的类型
	k := v.Kind()
	fmt.Println("具体类型是：", k)

	switch k {
	case reflect.Float64:
		v.SetFloat(3.14)
		fmt.Println("a is float64:", v.Float())
	case reflect.String:
		fmt.Println("a is string:", v.String())
	case reflect.Ptr:
		v.Elem().SetFloat(3.1415)
		// elem获取地址指向的值
		fmt.Println("a is float64:", v.Elem().Float())
		fmt.Println("a point:", v.Pointer())
	}
}

/*结构体和反射*/
type Boy struct {
	// 匿名字段
	User
	Addr string
}

type User struct {
	Id       int
	Name     string
	Age      int
	Birthday time.Time
}

func (u User) Hello() {
	fmt.Println("hello ", u.Name)
}

func (u User) SetAge(age int) {
	fmt.Println("接收到参数：", age)
	u.Age = age
}

func Poni(o interface{}) {
	t := reflect.TypeOf(o)
	fmt.Println("类型：", t)
	fmt.Println("字符串类型：", t.Name())
	// 获取值
	v := reflect.ValueOf(o)
	fmt.Println("获取值：", v)

	// 可以获取所有属性
	for i := 0; i < t.NumField(); i++ {
		// 每一个字段
		f := t.Field(i)
		// 每一个字段值信息
		val := v.Field(i).Interface()
		fmt.Printf("FiledName = %s , FiledType =  %v, val = %v\n", f.Name, f.Type, val)
	}
	// 获取所有方法
	for i := 0; i < t.NumMethod(); i++ {
		m := t.Method(i)
		fmt.Printf("MethodName = %s , MethodType =  %v \n", m.Name, m.Type)
		m.Func.Call([]reflect.Value{v})
	}
}

func SerStructVal(o interface{}) {
	v := reflect.ValueOf(o)
	// 获取指针指向的元素
	v = v.Elem()
	f := v.FieldByName("Name")
	if f.Kind() == reflect.String {
		f.SetString("lily")
	}
}

func TestAnonymous() {
	m := Boy{User{2, "herry", 25, time.Now()}, "address"}
	t := reflect.TypeOf(m)
	fmt.Println(t)
	fmt.Println(t.Field(0))
	v := reflect.ValueOf(m)
	fmt.Println(v)
	fmt.Println(v.Field(0))
}

func TestCallMethod() {
	u := User{3, "jerry", 25, time.Now()}
	t := reflect.TypeOf(u)
	// v := reflect.ValueOf(u)
	// 获取方法
	// m := v.MethodByName("SetAge")
	m, ok := t.MethodByName("SetAge")
	if !ok {
		fmt.Println("method error reflect")
	}
	// 构建一些参数，没参数的情况下：var args2 []reflect.Value
	args := []reflect.Value{
		reflect.ValueOf(u),
		reflect.ValueOf(22),
	}
	// m.Call(args)
	m.Func.Call(args)
	b, _ := json.Marshal(u)
	fmt.Println(string(b))
}
